package com.hmall.common.utils;

import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.concurrent.ListenableFutureCallback;

import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
public class RabbitMqHelper {

    private final RabbitTemplate rabbitTemplate;

    public void sendMessage(String exchange, String routingKey, Object message) {
        log.debug("准备发送消息，exchange:{}, routingKey:{}, message:{}", exchange, routingKey, message);
        rabbitTemplate.convertAndSend(exchange, routingKey, message);
    }

    public void sendDelayMessage(String exchange, String routingKey, Object message, int delay) {
        log.debug("准备发送延迟消息，exchange:{}, routingKey:{}, message:{}, delay:{}", exchange, routingKey, message, delay);
        rabbitTemplate.convertAndSend(exchange, routingKey, message, m -> {
            m.getMessageProperties().setDelay(delay);
            return m;
        });
    }

    public void sendMessageWithConfirm(String exchange, String routingKey, Object message, int maxRetries) {
        log.debug("准备发送消息，exchange:{}, routingKey:{}, message:{}", exchange, routingKey, message);
        CorrelationData cd = new CorrelationData(IdUtil.simpleUUID());
        cd.getFuture().addCallback(new ListenableFutureCallback<>() {
            int retryCount = 0;
            @Override
            public void onFailure(Throwable ex) {
                log.error("处理ack失败", ex);
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                if (result != null && !result.isAck()) {
                    log.debug("消息发送失败， 收到nack，已重试次数：{}", retryCount);
                    if (retryCount >= maxRetries) {
                        log.debug("消息发送失败， 已重试次数：{}， 已放弃", maxRetries);
                        return;
                    }
                    CorrelationData cd = new CorrelationData(IdUtil.simpleUUID());
                    cd.getFuture().addCallback(this);
                    rabbitTemplate.convertAndSend(exchange, routingKey, message, cd);
                    retryCount++;
                }
            }
        });
        rabbitTemplate.convertAndSend(exchange, routingKey, message, cd);
    }

}
